package com.anlogic.sdk.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
import org.eclipse.ui.PlatformUI;
import com.anlogic.sdk.utils.toolchain.ToolchainUtils;
import com.google.gson.JsonObject;

@SuppressWarnings("restriction")
public class EnvUtils {
	public static String osType() {
		String os = Platform.getOS();
		if (Platform.OS_LINUX.equals(os)) {
			return Platform.OS_LINUX;
		} else if (Platform.OS_MACOSX.equals(os)) {
			return Platform.OS_MACOSX;
		} else if (Platform.OS_WIN32.equals(os)) {
			return Platform.OS_WIN32;
		}
		return Platform.OS_UNKNOWN;
	}

	public static String osName() {
		String osNameString = System.getProperty("os.name");
		return osNameString;
	}

	public static String locationPath() {
		return System.getProperty("user.dir");
	}

	public static boolean isWindows() {
		return osName().toLowerCase().contains("windows");
	}

	public static boolean isLinux() {
		return osName().toLowerCase().contains("linux");
	}

	public static String getEclipseHome() {
		String eclipseHome = System.getProperty("eclipse.home.location"); // file:/path
		if (isWindows()) {
			eclipseHome = eclipseHome.substring(6);
		}
		if (isLinux()) {
			eclipseHome = eclipseHome.substring(5);
		}
		return eclipseHome;
	}
	
	public static String getWorkspacePath() {
		String path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toString();
		return path;
	}
	
	public static IProject[] getWorkspaceProjects() {
		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		return root.getProjects();
	}
	
	public static IProject[] getAccessibleProjects() {
		List<IProject> projects = new ArrayList<IProject>();
		for (IProject proj : getWorkspaceProjects()) {
			if (proj.isAccessible()) {
				projects.add(proj);
			}
		}
		return projects.toArray(new IProject[0]);
	}
	
	public static IProject[] getInAccessibleProjects() {
		List<IProject> projects = new ArrayList<IProject>();
		for (IProject proj : getWorkspaceProjects()) {
			if (!proj.isAccessible()) {
				projects.add(proj);
			}
		}
		return projects.toArray(new IProject[0]);
	}
	
	public static IProject[] getUnMatchedProjects() {
		List<IProject> projects = new ArrayList<IProject>();
		for (IProject proj : getWorkspaceProjects()) {
			if (!isProjectLocMatched(proj)) {
				projects.add(proj);
			}
		}
		return projects.toArray(new IProject[0]);
	}
	
	public static boolean isProjectLocMatched(IProject proj) {
		String wsLoc = EnvUtils.getWorkspacePath();
		String projLoc = proj.getLocation().toString();
		String projName = projLoc.substring(projLoc.lastIndexOf("/") + 1);
		String wsProjLoc = wsLoc + "/" + projName;
		File projFile = new File(projLoc);
		File wsProjFile = new File(wsProjLoc);
		
		if (proj.isAccessible()) {
			if (!projFile.exists()) {
				return false;
			}
			if (!wsProjFile.exists()) {
				return true;
			}
			if (wsProjFile.equals(projFile)) {
				return true;
			}
		}
		return false;
	}
	
	public static void importProject(String projLoc) throws CoreException {
		IProjectDescription description = ResourcesPlugin.getWorkspace().loadProjectDescription(new Path(projLoc + "/.project"));
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(description.getName());
		if (project.exists() && project.isOpen()) {
			return;
		}
		project.create(description, null);
		project.open(null);
	}
	
	public static String getIDERootPath() {
		return System.getenv("IDE_ROOT_PATH");
	}

	public static String getIDEToolPath() {
		return System.getenv("IDE_TOOL_PATH");
	}
	
	public static String getBspResourcePath() {
		return System.getenv("BSP_RESOURCE_PATH");
	}

	public static Map<String, String> setIntoPath(String path) {
		Map<String, String> envMap = System.getenv();
		String defaultDelimiter = System.getProperty("path.separator");
		String valToSet = String.valueOf(path) + defaultDelimiter + envMap.get("PATH");
		envMap.put("PATH", valToSet);
		return envMap;
	}

	public static void setEnv(String key, String value) {
		System.setProperty(key, value);
	}

	public static String getExcuteExtend() {
		String extName = "";
		if (isWindows()) {
			extName = ".exe";
		}
		return extName;
	}
	
	public static String getCmdScriptExtend() {
		String extName = "";
		if (isWindows()) {
			extName = ".bat";
		}
		return extName;
	}
	
	public static String getIDEVersion() {
		String version = "";
		try {
			String path = FileUtils.getPluginResourcePath("com.anlogic.sdk.product", "about.mappings");
			BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
			try {
				while (true) {
					String line = reader.readLine();
					if (line == null)
						break;
					if (line.startsWith("1=")) {
						version = line.substring(2);
						break;
					}
				}
			} finally {
				reader.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return version;
	}
	
	public static String getIDEBuildId() {
		String buildId = "";
		try {
			String path = FileUtils.getPluginResourcePath("com.anlogic.sdk.product", "about.mappings");
			BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
			try {
				while (true) {
					String line = reader.readLine();
					if (line == null)
						break;
					if (line.startsWith("0=")) {
						buildId = line.substring(2);
						break;
					}
				}
			} finally {
				reader.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return buildId;
	}
	
	public static void addIDEVersionToMakefile(String filePath) {
		File file = new File(filePath);
		if (!file.exists()) {
			return;
		}
		String content = FileUtils.read(file);
		
        Pattern pattern = Pattern.compile("SDK_VERSION\\s*=\\s*\\d+");
        Matcher matcher = pattern.matcher(content);
        
        String newVersion = "SDK_VERSION = " + EnvUtils.getIDEBuildId();
        if (matcher.find()) {
        	content = matcher.replaceAll(newVersion);
        } else {
        	if (content.contains("-DSDK_VERSION")) {
        		content = newVersion + "\n" + content;
        	} else {
        		content = newVersion + "\nAL_CFLAGS += -DSDK_VERSION=$(SDK_VERSION)\n" + content;
        	}
        }
        
        FileUtils.write(file, content);
	}
	
	public static String resolveDynamicVariable(String input) {
		String output = input;
		if (input.indexOf("${") >= 0) {
			Map<String, String> envMap = System.getenv();
			for (String key : envMap.keySet()) {
				if (input.indexOf("${" + key + "}") >= 0) {
					output = output.replaceAll("[$][{]" + key + "[}]", envMap.get(key));
					break;
				}
			}
		}
		return output;
	}
	
	public static boolean checkOpenocd() {
		try {
			String openocd = ToolchainUtils.getOpenOCDExecutable();
			openocd = resolveDynamicVariable(openocd);
			if (openocd == null || openocd.isEmpty() || !FileUtils.checkFileExists(openocd)) {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
	public static boolean isDarkTheme() {
	    try {
	        IThemeEngine themeEngine = PlatformUI.getWorkbench().getService(IThemeEngine.class);
	        if (themeEngine != null) {
	            String activeTheme = themeEngine.getActiveTheme().getLabel();
	            if (activeTheme != null && activeTheme.toLowerCase().contains("dark")) {
	            	return true;
	            }
	        }
	    } catch (Exception e) {
	    	return false;
	    }
	    return false;
    }
	
	public static List<String> checkEnv() {
		List<String> errors = new ArrayList<>();
		File envFile = new File(getIDERootPath() + "/tools/data/environments.json");
		if (!envFile.exists()) {
			errors.add("Environment file not found: " + envFile.getAbsolutePath());
			return errors;
		}
		JsonObject envObj = JsonUtils.readJsonFile(envFile);
		if (envObj == null) {
			errors.add("Environment file read failed!");
			return errors;
		}
		
		for (String key : envObj.keySet()) {
			JsonObject element = envObj.get(key).getAsJsonObject();
			if (element == null) {
				errors.add("Environment variable " + key + " is not set.");
			} else {
				boolean executable = element.get("executable").getAsBoolean();
				boolean readable = element.get("readable").getAsBoolean();
				boolean writable = element.get("writable").getAsBoolean();
				if (element.get("path").isJsonArray()) {
					element.get("path").getAsJsonArray().forEach(pathElement -> {
						String path = pathElement.getAsString();
						path = resolveDynamicVariable(path);
						if (path == null || path.isEmpty()) {
							errors.add("Environment variable " + key + " path element is empty.");
						} else {
							File file = new File(path);
							if (!file.exists()) {
								errors.add("Environment variable " + key + " path does not exist: " + path);
							} else {
								if (executable && !file.canExecute()) {
									errors.add("Environment variable " + key + " path is not executable: " + path);
								}
								if (readable && !file.canRead()) {
									errors.add("Environment variable " + key + " path is not readable: " + path);
								}
								if (writable && !file.canWrite()) {
									errors.add("Environment variable " + key + " path is not writable: " + path);
								}
								if (!executable && writable && file.canWrite() && readable && file.canRead()) {
									if (FileUtils.isEncrypted(path)) {
										errors.add("Environment variable " + key + " path is likely encrypted: " + path);
									}
								}
							}
						}
					});
				} else {
					String path = element.get("path").getAsString();
					if (path == null || path.isEmpty()) {
						errors.add("Environment variable " + key + " path element is empty.");
					} else {
						path = resolveDynamicVariable(path);
						File file = new File(path);
						if (!file.exists()) {
							errors.add("Environment variable " + key + " path does not exist: " + path);
						} else {
							if (executable && !file.canExecute()) {
								errors.add("Environment variable " + key + " path is not executable: " + path);
							}
							if (readable && !file.canRead()) {
								errors.add("Environment variable " + key + " path is not readable: " + path);
							}
							if (writable && !file.canWrite()) {
								errors.add("Environment variable " + key + " path is not writable: " + path);
							}
							if (!executable && writable && file.canWrite() && readable && file.canRead()) {
								if (FileUtils.isEncrypted(path)) {
									errors.add("Environment variable " + key + " path is likely encrypted: " + path);
								}
							}
						}
					}
				}
			}
		}
		
		return errors;
	}
}
